function b = check_cache_consistency(mdl, tol, op)
%CHECK_CACHE_CONSISTENCY A function to check consistency of cache
%
% [ Syntax ]
%   - b = check_cache_consistency(mdl, tol)
%   - b = check_cache_consistency(mdl, tol, 'quiet');
%
% [ Remarks ]
%   - It is an internal function for debugging, which is not for use.
%
% [ History ]
%   - Created by Dahua Lin, on Dec 25, 2007
%

%% skeleton

verbose = true;
if nargin >= 3
    if ischar(op) && strcmp(op, 'quiet')
        verbose = false;
    end
end


if numel(mdl) > 1
    
    for i = 1 : numel(mdl)
        b = check_cache_consistency(mdl(i), tol);
        if ~b
            report(verbose, 'Cache checking for model %d failed.', i);
            return;
        end
    end
    
    b = true;
    report(verbose, 'All checking passes!');
    return;
    
else  % single model
    
    b = false;
    
    if ~(mdl.clevel == 0 || mdl.clevel == 1 || mdl.clevel == 2)
        report(verbose, 'Invalid cachelevel %d', mdl.clevel);
        return;
    end
    
    switch mdl.clevel
        case 0
            if ~do_check('L0', mdl, [0 0 0 0 0], tol, verbose);
                return;
            end
        case 1
            if ~do_check('L1', mdl, [1 1 0 0 1], tol, verbose);
                return;
            end
        case 2
            if ~do_check('L2', mdl, [1 1 1 1 1], tol, verbose);
                return;
            end
    end                        
    
    b = true;
    return;
    
end


%% item - checking functions

function b = check_ldsm(mdl, tol)

b = approx(log(det(getcov(mdl))), mdl.ldsm, tol);

function b = check_trsm(mdl, tol)

b = approx(trace(getcov(mdl)), mdl.trsm, tol);

function b = check_invsm(mdl, tol)

b = approx(mdl.invsm .* mdl.sigma, ones(getdim(mdl), 1), tol);

function b = check_ism_mu(mdl, tol)

b = approx(mdl.ism_mu, diag(1 ./ mdl.sigma) * mdl.mu, tol);

function b = check_mu_ism_mu(mdl, tol)

b = approx(mdl.mu_ism_mu, mdl.mu' * diag(1 ./ mdl.sigma) * mdl.mu, tol);


%% auxiliary function


function b = do_check(levelname, mdl, should_cache, tol, verbose)

b = false;
items = {'ldsm', 'trsm', 'invsm', 'ism_mu', 'mu_ism_mu'};
funs = {@check_ldsm, @check_trsm, @check_invsm, @check_ism_mu, @check_mu_ism_mu};

% check emptiness

for i = 1 : length(items)
    
    citem = items{i};
    
    if should_cache(i)
        if isempty(mdl.(citem))
            report(verbose, '%s is empty for %s', citem, levelname);
            return;
        end
    else
        if ~isempty(mdl.(citem))
            report(verbose, '%s is not empty for %s', citem, levelname);
            return;
        end
    end
        
end

% check integrity of items

for i = find(should_cache)
    
    cfun = funs{i};
    
    if ~cfun(mdl, tol)
        report(verbose, 'The checking of item %s does not pass', items{i});
        return;
    end    
end

b = true;
return;


function report(verbose, msg, varargin)

if verbose
    disp(sprintf(msg, varargin{:}));
end


function b = approx(x, y, tol)

b = isequal(size(x), size(y)) && max(abs(x(:) - y(:))) < tol;




    
